package test.algorithm.FastSlowPointer;

import java.util.LinkedList;
import java.util.Queue;

/**
 * 图的广度优先遍历
 * @author serenity
 *
 */
public class Graph2 {


	// 存储节点信息
	private char[] vertices;
	
	// 存储边信息（邻接矩阵）
	private  int[][] arcs;
	
	// 图的节点数
	private int vexnum;
	
	// 记录节点是否已被遍历
	private boolean[] visited;
	
	// 初始化
	public Graph2(int n) {
		  vexnum = n;
		  vertices = new char[n];
		  arcs = new int[n][n];
		  visited = new boolean[n];
		  for (int i = 0; i < vexnum; i++) {
		     for (int j = 0; j < vexnum; j++) {
		     arcs[i][j] = 0;
		     }
		  }

	}
	
	// 添加边(无向图)
	public void addEdge(int i, int j) {
		  // 边的头尾不能为同一节点
		  if (i == j)return;
		  
		  arcs[i][j] = 1;
		  arcs[j][i] = 1;
	}
	
	// 设置节点集
	public void setVertices(char[] vertices) {
		this.vertices = vertices;
	}
	
	// 设置节点访问标记
	public void setVisited(boolean[] visited) {
		this.visited = visited;
	}

	// 打印遍历节点
	public void visit(int i){
		System.out.print(vertices[i] + " ");
	}
	
	// 广度优先遍历
	public void BFSTraverse(){
		// 初始化节点遍历标记
		for(int i=0;i<vexnum;i++){
			visited[i] = false;
		}
		
		//创建队列
		Queue<Integer> queue = new LinkedList<Integer>();
		
		for(int i=0;i<vexnum;i++){
			if(visited[i]==false){
				// 联通子图起始节点入队
				queue.add(i);
				visited[i] = true;
				
				while(!queue.isEmpty()){
					//队列节点出队
					int curr = queue.remove();
					//打印
					visit(curr);
					
					//该节点所有还没入队的子节点在队尾
					for(int j=0;j<vexnum;j++){
						if(arcs[curr][j]==1 && visited[j]==false){
							queue.add(j);
							visited[j] = true;
						}
					}
				}
			}
		}
	}
	
	public static void main(String[] args) {
		Graph2 g = new Graph2(9);
		char[] vertices = {'A','B','C','D','E','F','G','H','I'};
		g.setVertices(vertices);
		
		g.addEdge(0, 1);
		g.addEdge(0, 5);
		g.addEdge(1, 0);
		g.addEdge(1, 2);
		g.addEdge(1, 6);
		g.addEdge(1, 8);
		g.addEdge(2, 1);
		g.addEdge(2, 3);
		g.addEdge(2, 8);
		g.addEdge(3, 2);
		g.addEdge(3, 4);
		g.addEdge(3, 6);
		g.addEdge(3, 7);
		g.addEdge(3, 8);
		g.addEdge(4, 3);
		g.addEdge(4, 5);
		g.addEdge(4, 7);
		g.addEdge(5, 0);
		g.addEdge(5, 4);
		g.addEdge(5, 6);
		g.addEdge(6, 1);
		g.addEdge(6, 3);
		g.addEdge(6, 5);
		g.addEdge(6, 7);
		g.addEdge(7, 3);
		g.addEdge(7, 4);
		g.addEdge(7, 6);
		g.addEdge(8, 1);
		g.addEdge(8, 2);
		g.addEdge(8, 3);
		
		System.out.print("广度优先遍历（递归）：");
		g.BFSTraverse();
	
	}


}
